package com.service;

import static com.def.GenericDef.EMPTY_CARRIER;
import static com.def.GenericDef.EVT_CUT_ADD_PANEL;
import static com.def.GenericDef.EVT_CUT_Delete_PANEL;
import static com.def.GenericDef.E_BIS_OPE;
import static com.def.GenericDef.E_READ_NOT_FOUND;
import static com.def.GenericDef.E_RET_BOX;
import static com.def.GenericDef.E_RET_PRD_INFO;
import static com.def.GenericDef.E_XPCUTOPE_BOX_MOVE_OUT_FAILED;
import static com.def.GenericDef.E_XPCUTOPE_BOX_NOT_REAL_EMPT;
import static com.def.GenericDef.E_XPCUTOPE_CREATE_BOX_FAILED;
import static com.def.GenericDef.E_XPCUTOPE_INPUT_PRD_CNT_INVALIED;
import static com.def.GenericDef.E_XPCUTOPE_INPUT_PRD_LIST_INVALIED;
import static com.def.GenericDef.E_XPCUTOPE_INVALID_INPUT;
import static com.def.GenericDef.E_XPCUTOPE_NEW_LOT_ID_INVALIED_B;
import static com.def.GenericDef.E_XPCUTOPE_NEW_LOT_ID_INVALIED_L;
import static com.def.GenericDef.E_XPCUTOPE_NEW_LOT_ID_INVALIED_P;
import static com.def.GenericDef.E_XPCUTOPE_PANEL_MOVE_TO_BOX_FAILED;
import static com.def.GenericDef.E_XPCUTOPE_PRD_QTY_SUM_UNMATCH;
import static com.def.GenericDef.E_XPCUTOPE_PRD_STD_QTY_SUM_UNMATCH;
import static com.def.GenericDef.LOT_SPLIT_0;
import static com.def.GenericDef.PROC_EMPTY;
import static com.def.GenericDef.RETURN_CODE_OK;
import static com.def.GenericDef.RETURN_CODE_SET_ERROR;
import static com.def.GenericDef.RETURN_CODE_UNKNOWN;
import static com.def.GenericDef.RETURN_MESG_OK;
import static com.def.GenericDef.TRX_OUT;
import static com.def.GenericDef.T_XPCUTOPE;
import static com.def.GenericDef.T_XPMOVEOUT;
import static com.def.GenericDef.T_XPPNLOUT;
import static com.def.GenericDef._NORMAL;
import static com.def.GenericDef._OK;
import static com.def.GenericDef._SPACE;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.dao.IBisOpeDao;
import com.dao.IRetBoxDao;
import com.dao.IRetPrdInfoDao;
import com.dao.IRetPrdJgeDao;
import com.icim.service.ICIMBaseService;
import com.model.Bis_ope;
import com.model.Bis_opeId;
import com.model.Ret_box;
import com.model.Ret_prd_info;
import com.rtnBean.DefectInfoBeen;
import com.rtnBean.NotFoundRtnBeen;
import com.rtnBean.SimpleRtnBeen;
import com.tx.Xpcutope.XpcutopeI;
import com.tx.Xpcutope.XpcutopeIA;
import com.tx.Xpcutope.XpcutopeIA2;
import com.tx.Xpcutope.XpcutopeIA3;
import com.tx.Xpcutope.XpcutopeO;
import com.tx.Xpcutope.XpcutopeOA;
import com.tx.Xpmagbox.XpmagboxI;
import com.tx.Xpmagbox.XpmagboxO;
import com.tx.Xpmoveout.XpmoveoutI;
import com.tx.Xpmoveout.XpmoveoutO;
import com.tx.Xppnlout.XppnloutI;
import com.tx.Xppnlout.XppnloutIA;
import com.tx.Xppnlout.XppnloutO;
import com.util.GUIDGenerator;
import com.util.MqOpe;
import com.util.Util;

@Scope("prototype")
@Service("XpcutopeService")
public class XpcutopeService extends ICIMBaseService{
	private static Logger logger = Logger.getLogger(XpcutopeService.class);
	private static String TX_NAME = T_XPCUTOPE;

	private XpcutopeI inTrx;
	private XpcutopeO outTrx;
	private MqOpe mqOpe;

	private String gszMsgBuf = "";
	private Timestamp gEvtTimestamp;
	private Double gEvtTimeD;
	private String gEvtSeqID;

	@Autowired
	private IRetBoxDao retBoxDao;
	@Autowired
	private IRetPrdInfoDao retPrdInfoDao;
	@Autowired
	private IBisOpeDao bisOpeDao;
	@Autowired
	private IRetPrdJgeDao retPrdJgeDao;

	@Autowired
	private XpmagboxService xpmagboxService;
	@Autowired
	private XppnloutService xppnloutService;
	@Autowired
	private XpmoveoutService xpmoveoutService;

	public String subMainProc(String strInMsg) {
		long rtnCode = _NORMAL;

		String outMsg = null;
		gszMsgBuf = "";
		gEvtTimestamp = Util.getCurrentTimestamp();
		gEvtTimeD = Util.getDoubleTime();
		gEvtSeqID = GUIDGenerator.javaGUID();
		inTrx = new XpcutopeI();
		outTrx = new XpcutopeO();
		outTrx.setTrx_id(TX_NAME);
		outTrx.setType_id(TRX_OUT);
		outTrx.setRtn_code(String.valueOf(RETURN_CODE_SET_ERROR));
		mqOpe = new MqOpe();

		try {
			inTrx = (XpcutopeI) mqOpe.inStr2Obj(strInMsg, inTrx);
			logger.info("InTrx is " + strInMsg);

			rtnCode = subMainProc2(inTrx.getAct_flg().toCharArray()[0]);
			if (rtnCode != _NORMAL) {
				TransactionAspectSupport.currentTransactionStatus()
						.setRollbackOnly();
				outTrx.setRtn_code(String.valueOf(rtnCode));
				outTrx.setRtn_mesg(gszMsgBuf);
			} else {
				outTrx.setRtn_code(String.valueOf(RETURN_CODE_OK));
				outTrx.setRtn_mesg(RETURN_MESG_OK);
				retPrdInfoDao.flushCurSession();
			}
		} catch (Exception ex) {
			TransactionAspectSupport.currentTransactionStatus()
					.setRollbackOnly();
			outTrx.setRtn_mesg(ex.toString());
			outTrx.setRtn_code(RETURN_CODE_UNKNOWN);
			logger.error(Util.stackTraceToString(ex));
		} finally {
			outMsg = mqOpe.obj2Str(outTrx);
			return outMsg;
		}
	}

	/**
	 * All move in logic
	 * 
	 * @return
	 */
	private long subMainProc2(char actionType) {
		long lRc = _NORMAL;

		switch (actionType) {
		case 'Q': {
			lRc = queryCutWip();
			if (lRc != _NORMAL) {
				return lRc;
			}
			break;
		}
		case 'O': { // Is first ope
			lRc = cutMoveOut();
			if (lRc != _NORMAL) {
				return lRc;
			}
			break;
		}
		case 'P': { // Not first ope
			lRc = cutMoveOut2();
			if (lRc != _NORMAL) {
				return lRc;
			}
			break;
		}
		default: {
			gszMsgBuf = "Invalide type input: [" + actionType + "]";
			return E_XPCUTOPE_INVALID_INPUT;
		}
		}

		return lRc;
	}

	// Distinct
	private long queryCutWip() {
		long lRc = _NORMAL;

		// Get lot list
		Bis_ope bis_ope = new Bis_ope();
		Bis_opeId bis_opeId = new Bis_opeId();
		bis_opeId.setOpe_id(inTrx.getCr_ope_id());
		bis_opeId.setOpe_ver(inTrx.getCr_ope_ver());

		bis_ope = bisOpeDao.get(bis_opeId);
		if (null == bis_ope) {
			gszMsgBuf = new NotFoundRtnBeen(bis_opeId.toString(), Bis_ope.class)
					.toString();
			return E_BIS_OPE + E_READ_NOT_FOUND;
		}

		List<String> lotList = new ArrayList<String>();
		String sql = "SELECT DISTINCT lot_id FROM Ret_prd_info WHERE prd_stat='INPR' AND cr_ope_id_fk='"
				+ inTrx.getCr_ope_id()
				+ "' AND cr_ope_ver_fk = '"
				+ inTrx.getCr_ope_ver() + "'";

		if (!Util.isSpaceCheck(inTrx.getWo_id())) {
			sql = sql + " AND wo_id_fk='" + inTrx.getWo_id() + "'";
		}
		if (!Util.isSpaceCheck(inTrx.getLot_id())) {
			sql = sql + " AND lot_id='" + inTrx.getLot_id() + "'";
		}

		lotList = retPrdInfoDao.findDistStringList(sql);
		if (!lotList.isEmpty()) {
			List<XpcutopeOA> oary = new ArrayList<XpcutopeOA>();
			for (String lot_id : lotList) {
				XpcutopeOA xpcutopeOA = new XpcutopeOA();
				xpcutopeOA.setLot_id(lot_id);
				oary.add(xpcutopeOA);
			}
			outTrx.setOary(oary);
			outTrx.setLot_cnt(lotList.size());
		} else {
			outTrx.setLot_cnt(0);
		}

		return lRc;
	}

	/**
	 * Cut move out: Not for first cut ope
	 * 
	 * @return
	 */
	private long cutMoveOut2() {// TODO Need modify
		long lRc = _NORMAL;
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		List<Ret_prd_info> prd_list = new ArrayList<Ret_prd_info>();
		Ret_box out_box = new Ret_box();
		Ret_prd_info prd = new Ret_prd_info();

		// Get current prd id.
		String prdId = "";
		if (inTrx.getIaryLot().isEmpty()) {
			gszMsgBuf = "Input lot list is empty!";
			if (Util.isSpaceCheck(inTrx.getIaryLot().get(0).getNew_lot_id())) {
				gszMsgBuf = "Input lot id is empty!";
			}
			return E_XPCUTOPE_INPUT_PRD_LIST_INVALIED;
		} else {
			prdId = inTrx.getIaryLot().get(0).getNew_lot_id();
		}

		// Check Box is EMPT
		rtn = cutOutBoxChk(prdId);
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		} else {
			out_box = (Ret_box) rtn.getObj();
		}

		// Get prd
		rtn = cutOutPrdGet(prdId);
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		} else {
			prd = (Ret_prd_info) rtn.getObj();
			prd_list.add(prd);
		}

		// Panel move to box
		rtn = moveToBox(out_box.getBox_id());
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}

		// Box move out
		rtn = moveOutBox(out_box.getBox_id());
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}
		// Save defect by new lot
		rtn = saveCutJudges(inTrx.getIaryLot(), prd_list);
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}

		// Set out trx
		rtn = setOutTrx();
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}
		return lRc;
	}

	/**
	 * Query Prd info
	 * 
	 * @param prd_id
	 * @return SimpleRtnBeen{Ret_prd_info}
	 */
	private SimpleRtnBeen cutOutPrdGet(String prd_id) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		Ret_prd_info prd = new Ret_prd_info();
		prd = retPrdInfoDao.get(prd_id);
		if (null == prd) {
			gszMsgBuf = new NotFoundRtnBeen(prd_id, Ret_prd_info.class)
					.toString();
			return new SimpleRtnBeen(E_RET_PRD_INFO + E_READ_NOT_FOUND,
					gszMsgBuf);
		}
		rtn.setObj(prd);

		return rtn;
	}

	/**
	 * Cout out box must EMPT, not first ope
	 * 
	 * @param out_lot_id
	 * @return SimpleRtnBeen{Ret_box}
	 */
	private SimpleRtnBeen cutOutBoxChk(String out_lot_id) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		Ret_box out_box = new Ret_box();

		out_box = retBoxDao.get(out_lot_id);
		if (null == out_box) {
			gszMsgBuf = new NotFoundRtnBeen(out_lot_id, Ret_box.class)
					.toString();
			return new SimpleRtnBeen(E_RET_BOX + E_READ_NOT_FOUND, gszMsgBuf);
		}

		if (!PROC_EMPTY.equals(out_box.getBox_stat())
				|| !EMPTY_CARRIER.equals(out_box.getReal_emp())) {
			gszMsgBuf = "Box [" + out_lot_id + "] must real empt ["
					+ PROC_EMPTY + "][" + EMPTY_CARRIER + "], but now is ["
					+ out_box.getBox_stat() + "][" + out_box.getReal_emp()
					+ "]";
			return new SimpleRtnBeen(E_XPCUTOPE_BOX_NOT_REAL_EMPT, gszMsgBuf);
		}

		rtn.setObj(out_box);

		return rtn;
	}

	/**
	 * Cut move out: Just for first cut ope
	 * 
	 * @return
	 */
	private long cutMoveOut() {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		List<Ret_prd_info> old_prd_list = new ArrayList<Ret_prd_info>();
		List<Ret_prd_info> new_prd_list = new ArrayList<Ret_prd_info>();
		Ret_box last_new_box = new Ret_box();
		Ret_prd_info clone_prd = new Ret_prd_info();

		// Check new lot id: not same as other sht_id,box_id,batch_no
		rtn = checkNewLots(inTrx.getIaryLot());
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}

		rtn = checkPnlQty();
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		} else {
			old_prd_list = (List<Ret_prd_info>) rtn.getObj();
			clone_prd = old_prd_list.get(0);
		}

		// Create new box
		rtn = createNewBoxs(inTrx.getIaryLot());
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		} else {
			last_new_box = (Ret_box) rtn.getObj(); // Last box
		}

		// Panel move to box
		rtn = moveToBox(last_new_box.getBox_id());
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}

		// Box move out
		rtn = moveOutBox(last_new_box.getBox_id());
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}

		// Delete prd cut panel
		rtn = delOldCutPanels(old_prd_list);
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}

		// Create new cut panel
		rtn = addNewCutPanels(clone_prd, inTrx.getIaryLot());
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		} else {
			new_prd_list = (List<Ret_prd_info>) rtn.getObj();
		}

		// Save defect by new lot
		rtn = saveCutJudges(inTrx.getIaryLot(), new_prd_list);
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}

		// Set out trx
		rtn = setOutTrx();
		if (_NORMAL != rtn.getlRc()) {
			gszMsgBuf = rtn.getMsgBuf();
			return rtn.getlRc();
		}
		return _NORMAL;
	}

	/**
	 * Check old panels's qty vs new panels's qty
	 * 
	 * @return SimpleRtnBeen{List<Ret_prd_info>}: Old prd list
	 */
	private SimpleRtnBeen checkPnlQty() {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		List<Ret_prd_info> old_prd_list = new ArrayList<Ret_prd_info>();
		int sumPrdQty = 0, sumPrdStdQty = 0, newPrdQty = 0, newPrdStdQty = 0;

		// Input count check
		if (0 < inTrx.getPrd_cnt() && !inTrx.getIary().isEmpty()
				&& inTrx.getPrd_cnt() == inTrx.getIary().size()) {
			;
		} else {
			gszMsgBuf = "Old prd count [" + inTrx.getPrd_cnt()
					+ "] and  prdlist count[" + inTrx.getIary().size()
					+ "] unmatch or invalied!";
			rtn.setMsgBuf(gszMsgBuf);
			rtn.setlRc(E_XPCUTOPE_INPUT_PRD_CNT_INVALIED);
			return rtn;
		}

		// Get old prd list
		for (XpcutopeIA prd : inTrx.getIary()) {
			Ret_prd_info old_prd = new Ret_prd_info();
			old_prd = retPrdInfoDao.get(prd.getPrd_seq_id());
			if (null == old_prd) {
				gszMsgBuf = new NotFoundRtnBeen(prd.getPrd_seq_id(),
						Ret_prd_info.class).toString();
				rtn.setMsgBuf(gszMsgBuf);
				rtn.setlRc(E_RET_PRD_INFO + E_READ_NOT_FOUND);
				return rtn;
			}
			sumPrdQty += old_prd.getPrd_qty();
			sumPrdStdQty += old_prd.getPrd_std_qty();

			old_prd_list.add(old_prd);
		}

		// Check new prds cnt
		for (XpcutopeIA2 lot : inTrx.getIaryLot()) {
			newPrdQty += lot.getPrd_qty();
			newPrdStdQty += lot.getPrd_std_qty();
		}

		if (sumPrdQty != newPrdQty) {
			gszMsgBuf = "Select prd's total count [" + sumPrdQty
					+ "] unmatch with new batch's total count [" + newPrdQty
					+ "]!";
			rtn.setMsgBuf(gszMsgBuf);
			rtn.setlRc(E_XPCUTOPE_PRD_QTY_SUM_UNMATCH);
			return rtn;
		}
		if (sumPrdStdQty != newPrdStdQty) {
			gszMsgBuf = "Select prd's total standard count [" + sumPrdStdQty
					+ "] unmatch with new batch's total standard count ["
					+ newPrdStdQty + "]!";
			rtn.setMsgBuf(gszMsgBuf);
			rtn.setlRc(E_XPCUTOPE_PRD_STD_QTY_SUM_UNMATCH);
			return rtn;
		}

		// Return old prd list
		rtn.setObj(old_prd_list);

		return rtn;
	}

	private SimpleRtnBeen setOutTrx() {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);

		outTrx.setEvt_timestamp(gEvtTimestamp);

		return rtn;
	}

	/**
	 * Save cut
	 * 
	 * @param iaryLot
	 * @param prd_list
	 * @return SimpleRtnBeen{_NORMAL}
	 */
	private SimpleRtnBeen saveCutJudges(List<XpcutopeIA2> iaryLot,
			List<Ret_prd_info> prd_list) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		for (XpcutopeIA2 lot : iaryLot) {
			if (null != lot.getIaryDef() && !lot.getIaryDef().isEmpty()) {
				for (Ret_prd_info prd : prd_list) {
					if (lot.getNew_lot_id().equals(prd.getPrd_seq_id())) {
						List<DefectInfoBeen> defectInfoList = new ArrayList<DefectInfoBeen>();
						for (XpcutopeIA3 def : lot.getIaryDef()) {
							if (!Util.isSpaceCheck(def.getDefectCode())) {
								DefectInfoBeen defectInfoBeen = new DefectInfoBeen();

								defectInfoBeen.setDefect_code(def
										.getDefectCode());
								defectInfoBeen.setDefect_cnt(def
										.getDefectCount());
								defectInfoList.add(defectInfoBeen);

							}
						}
						if (!defectInfoList.isEmpty()) {
							rtn = retPrdJgeDao.saveRetPrdJgeInfo(prd,
									defectInfoList, gEvtTimestamp);
						}
					}
				}
			}
		}

		return rtn;
	}

	/**
	 * Delete old cut panels
	 * 
	 * @param old_prd_list
	 * @return SimpleRtnBeen{_NORMAL}
	 */
	private SimpleRtnBeen delOldCutPanels(List<Ret_prd_info> old_prd_list) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);

		for (Ret_prd_info prd : old_prd_list) {
			prd.setLot_id(_SPACE);
			prd.setEvt_cate(EVT_CUT_Delete_PANEL);
			prd.setEvt_time_d(gEvtTimeD);
			prd.setEvt_timestamp(gEvtTimestamp);
			prd.setEvt_seq_id(gEvtSeqID);
			prd.setEvt_usr(inTrx.getEvt_user());

			retPrdInfoDao.delete(prd);
		}

		return rtn;
	}

	/**
	 * Clone new ret_prd_info records
	 * 
	 * @param clone_prd
	 * @param iaryLot
	 * @return SimpleRtnBeen{ List<Ret_prd_info> }
	 */
	private SimpleRtnBeen addNewCutPanels(Ret_prd_info clone_prd,
			List<XpcutopeIA2> iaryLot) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		List<Ret_prd_info> new_prd_list = new ArrayList<Ret_prd_info>();

		for (XpcutopeIA2 lot : iaryLot) {
			// Create new panel
			Ret_prd_info new_prd = new Ret_prd_info();
			new_prd = (Ret_prd_info) clone_prd.clone();
			new_prd.setPrd_seq_id(lot.getNew_lot_id());
			new_prd.setUnq_seq_id(GUIDGenerator.javaGUID());
			new_prd.setEvt_seq_id(gEvtSeqID);
			new_prd.setEvt_time_d(gEvtTimeD);
			new_prd.setEvt_timestamp(gEvtTimestamp);
			new_prd.setEvt_cate(EVT_CUT_ADD_PANEL);
			new_prd.setEvt_usr(inTrx.getEvt_user());

			new_prd.setLot_id(lot.getNew_lot_id());
			new_prd.setLot_splt_id(LOT_SPLIT_0);
			new_prd.setBox_id_fk(lot.getNew_lot_id());

			new_prd.setPrd_qty(lot.getPrd_qty());
			new_prd.setPrd_std_qty(lot.getPrd_std_qty());

			retPrdInfoDao.save(new_prd);
			new_prd_list.add(new_prd);

			// Update box info
			Ret_box new_box = retBoxDao.get(lot.getNew_lot_id());
			rtn = retBoxDao.configBoxInfo(new_box);
			if (_NORMAL != rtn.getlRc()) {
				return rtn;
			}

			new_box = (Ret_box) rtn.getObj();
			retBoxDao.update(new_box);
			// retBoxDao.getCrSession().merge(new_box);
		}

		rtn.setObj(new_prd_list);
		return rtn;
	}

	/**
	 * Clone new ret_prd_info record
	 * 
	 * @param box_id
	 * @return SimpleRtnBeen {Ret_prd_info}
	 */
	private SimpleRtnBeen addNewCutPanel(Ret_box new_box) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		SimpleRtnBeen rtn_box = new SimpleRtnBeen(_NORMAL);

		List<Ret_prd_info> prd_list = new ArrayList<Ret_prd_info>();
		Ret_prd_info new_prd = new Ret_prd_info();
		String box_id = new_box.getBox_id();

		prd_list = retPrdInfoDao.getShtListInfo(box_id);
		if (null == prd_list) {
			return new SimpleRtnBeen(E_RET_PRD_INFO + E_READ_NOT_FOUND,
					"Not panel in box [" + box_id + "], system error!");
		}

		// Create new box

		// Create new panel

		new_prd = (Ret_prd_info) prd_list.get(0).clone();
		// new_prd = ped_list.get(0);
		new_prd.setPrd_seq_id(box_id);
		new_prd.setUnq_seq_id(GUIDGenerator.javaGUID());
		new_prd.setEvt_seq_id(gEvtSeqID);
		new_prd.setEvt_time_d(gEvtTimeD);
		new_prd.setEvt_timestamp(gEvtTimestamp);
		new_prd.setEvt_cate(EVT_CUT_ADD_PANEL);
		new_prd.setEvt_usr(inTrx.getEvt_user());

		new_prd.setLot_id(box_id);
		new_prd.setLot_splt_id(LOT_SPLIT_0);
		new_prd.setBox_id_fk(box_id);

		int new_prd_qty = 0;

		for (Ret_prd_info prd : prd_list) {
			new_prd_qty += prd.getPrd_qty();
			prd.setBox_id_fk(_SPACE);
			prd.setLot_id(_SPACE);
			// prd.setPrd_stat() //TODO New status?
			prd.setEvt_cate(EVT_CUT_Delete_PANEL);
			prd.setEvt_time_d(gEvtTimeD);
			prd.setEvt_timestamp(gEvtTimestamp);
			prd.setEvt_seq_id(gEvtSeqID);
			prd.setEvt_usr(inTrx.getEvt_user());

			retPrdInfoDao.delete(prd);
		}

		new_prd.setPrd_qty(new_prd_qty);
		rtn.setObj(new_prd);
		retPrdInfoDao.save(new_prd);

		rtn_box = retBoxDao.configBoxInfo(new_box);
		if (_NORMAL != rtn.getlRc()) {
			return rtn;
		}

		new_box = (Ret_box) rtn_box.getObj();
		retBoxDao.getCrSession().merge(new_box);
		// retBoxDao.update(new_box);

		return rtn;
	}

	/**
	 * Check new lots
	 * 
	 * @param iaryLot
	 * @return SimpleRtnBeen{_NORMAL}
	 */
	private SimpleRtnBeen checkNewLots(List<XpcutopeIA2> iaryLot) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		for (XpcutopeIA2 lot : iaryLot) {
			rtn = checkNewLot(lot.getNew_lot_id());
			if (_NORMAL != rtn.getlRc()) {
				return rtn;
			}
		}

		return new SimpleRtnBeen(_NORMAL);
	}

	/**
	 * Check new lot id: not same as other sht_id,box_id,batch_no
	 * 
	 * @param new_lot_id
	 * @return
	 */
	private SimpleRtnBeen checkNewLot(String new_lot_id) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);

		// box
		if (null != retBoxDao.get(new_lot_id)) {
			return new SimpleRtnBeen(E_XPCUTOPE_NEW_LOT_ID_INVALIED_B,
					"New batch id can't same as exist box id, box ["
							+ new_lot_id + "] already exist!");
		}

		// panel
		if (null != retPrdInfoDao.get(new_lot_id)) {
			return new SimpleRtnBeen(E_XPCUTOPE_NEW_LOT_ID_INVALIED_P,
					"New batch id can't same as exist panel id, panel ["
							+ new_lot_id + "] already exist!");
		}

		// batch
		List<Ret_prd_info> chkPrdList = new ArrayList<Ret_prd_info>();
		String sql = "FROM Ret_prd_info WHERE lot_id='" + new_lot_id + "'";

		chkPrdList = retPrdInfoDao.find(sql, 0, 1);
		if (!chkPrdList.isEmpty()) {
			return new SimpleRtnBeen(E_XPCUTOPE_NEW_LOT_ID_INVALIED_L,
					"New batch id can't same as exist batch id, panel ["
							+ chkPrdList.get(0).getPrd_seq_id()
							+ "]'s batch no is [" + new_lot_id + "]!");
		}

		return rtn;
	}

	private SimpleRtnBeen moveOutBox(String box_id) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		MqOpe mqOpe_XPMOVEOUT = new MqOpe();

		XpmoveoutI xpmoveoutI = new XpmoveoutI();
		XpmoveoutO xpmoveoutO = new XpmoveoutO();
		xpmoveoutI.setTrx_id(T_XPMOVEOUT);
		xpmoveoutI.setEvt_usr(inTrx.getEvt_user());
		xpmoveoutI.setBox_id(box_id);
		xpmoveoutI.setTool_id(inTrx.getTool_id());
		xpmoveoutI.setJump_ope_id(inTrx.getJump_ope_id());
		xpmoveoutI.setJump_ope_ver(inTrx.getJump_ope_ver());
		xpmoveoutI.setRemark(inTrx.getRemark());
		xpmoveoutI.setRwk_id(inTrx.getRwk_id());

		String outMsg = xpmoveoutService.subMainProc(mqOpe_XPMOVEOUT
				.obj2Str(xpmoveoutI));
		xpmoveoutO = (XpmoveoutO) mqOpe_XPMOVEOUT.inStr2Obj(outMsg, xpmoveoutO);
		if (!xpmoveoutO.getRtn_code().equals(RETURN_CODE_OK)) {
			return new SimpleRtnBeen(E_XPCUTOPE_BOX_MOVE_OUT_FAILED,
					"Send xpmoveoutService to add box failed:["
							+ xpmoveoutO.getRtn_mesg() + "]["
							+ xpmoveoutO.getRtn_code() + "] !");
		}

		return rtn;
	}

	/**
	 * Send msg to xppnlout
	 * 
	 * @return
	 */
	private SimpleRtnBeen moveToBox(String box_id) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		MqOpe mqOpe_XPPNLOUT = new MqOpe();

		XppnloutI xppnloutI = new XppnloutI();
		XppnloutO xppnloutO = new XppnloutO();
		xppnloutI.setTrx_id(T_XPPNLOUT);
		xppnloutI.setBox_id(box_id);
		xppnloutI.setEvt_usr(inTrx.getEvt_user());
		xppnloutI.setPnl_cnt(inTrx.getPrd_cnt());

		if (inTrx.getPrd_cnt() > 0) {
			List<XppnloutIA> xppnloutIA = new ArrayList<XppnloutIA>();

			for (XpcutopeIA iary : inTrx.getIary()) {
				XppnloutIA iaryTo = new XppnloutIA();
				iaryTo.setPrd_seq_id(iary.getPrd_seq_id());
//				iaryTo.setDefCnt(0);
				iaryTo.setJudge_result(_OK);

				xppnloutIA.add(iaryTo);
			}

			xppnloutI.setIary(xppnloutIA);
			xppnloutI.setPnl_cnt(xppnloutIA.size());
		}

		String outMsg = xppnloutService.subMainProc(mqOpe_XPPNLOUT
				.obj2Str(xppnloutI));
		xppnloutO = (XppnloutO) mqOpe_XPPNLOUT.inStr2Obj(outMsg, xppnloutO);
		if (!xppnloutO.getRtn_code().equals(RETURN_CODE_OK)) {
			return new SimpleRtnBeen(E_XPCUTOPE_PANEL_MOVE_TO_BOX_FAILED,
					"Send xppnloutService failed:{"
							+ xppnloutO.getRtn_mesg() + "}, Error code:{"
							+ xppnloutO.getRtn_code() + "} !");
		}

		return rtn;
	}

	/**
	 * Create new boxes for cut
	 * 
	 * @param iaryLot
	 * @return SimpleRtnBeen{Ret_box}
	 */
	private SimpleRtnBeen createNewBoxs(List<XpcutopeIA2> iaryLot) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		for (XpcutopeIA2 lot : iaryLot) {
			rtn = createNewBox(lot.getNew_lot_id());
			if (_NORMAL != rtn.getlRc()) {
				return rtn;
			}
		}

		return rtn;
	}

	/**
	 * Create new box for cut
	 * 
	 * @param box_id
	 * @return SimpleRtnBeen{Ret_box}
	 */
	private SimpleRtnBeen createNewBox(String box_id) {
		SimpleRtnBeen rtn = new SimpleRtnBeen(_NORMAL);
		MqOpe mqOpe_XPMAGBOX = new MqOpe();

		XpmagboxI xpmagboxI = new XpmagboxI();
		XpmagboxO xpmagboxO = new XpmagboxO();
		xpmagboxI.setTrx_id("XPMAGBOX");
		xpmagboxI.setAction_flg("A");
		xpmagboxI.setBox_id(box_id);
		xpmagboxI.setBox_size("WIRE");
		String outMsg = xpmagboxService.subMainProc(mqOpe_XPMAGBOX
				.obj2Str(xpmagboxI));
		xpmagboxO = (XpmagboxO) mqOpe_XPMAGBOX.inStr2Obj(outMsg, xpmagboxO);
		if (!xpmagboxO.getRtn_code().equals(RETURN_CODE_OK)) {
			return new SimpleRtnBeen(E_XPCUTOPE_CREATE_BOX_FAILED,
					"Send xpmagboxService to add box failed:["
							+ xpmagboxO.getRtn_mesg() + "]["
							+ xpmagboxO.getRtn_code() + "] !");
		}

		if (1 != xpmagboxO.getTbl_cnt()) {
			return new SimpleRtnBeen(E_XPCUTOPE_CREATE_BOX_FAILED,
					"Send xpmagboxService to add box failed, tbl_cnt ["
							+ xpmagboxO.getTbl_cnt() + "] not 1.");
		} else {
			rtn.setObj(xpmagboxO.getOary().get(0));
		}

		return rtn;
	}
	// TODO Change service call -> http call
	// Can be catch by AOP, so MQ won't be send

}
